
using Nop.Core;
using Nop.Core.Caching;
using Nop.Core.Data;
using Nop.Core.Domain.XJ;
using Nop.Data;
using Nop.Services.Events;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Nop.Services.XJ
{
	/// <summary>
	/// XJEquipmentStock service
	/// </summary>
	public partial class XJEquipmentStockService : IXJEquipmentStockService
	{
		#region Constants

		/// <summary>
		/// Key for caching
		/// </summary>
		private const string XJEQUIPMENTSTOCKS_ALL_KEY = "Nop.xjequipmentstock.all";
		/// <summary>
		/// Key for caching
		/// </summary>
		/// <remarks>
		/// {0} : xJEquipmentStock ID
		/// </remarks>
		private const string XJEQUIPMENTSTOCK_BY_ID_KEY = "Nop.xjequipmentstock.id-{0}";
		/// <summary>
		/// Key pattern to clear cache
		/// </summary>
		private const string XJEQUIPMENTSTOCKS_PATTERN_KEY = "Nop.xjequipmentstock.";
		#endregion

		#region Fields
		private readonly IRepository<XJEquipmentStock> _xJEquipmentStockRepository;
		private readonly IRepository<XJEquipment> _xJEquipmentRepository;
		private readonly IRepository<XJPlace> _xJPlaceRepository;
		private readonly IEventPublisher _eventPublisher;
		private readonly ICacheManager _cacheManager;
		private readonly IXJEquipmentCategoryService _xJEquipmentCategoryService;
		private readonly IDbContext _dbContext;
		#endregion

		#region Ctor

		/// <summary>
		/// Ctor
		/// </summary>
		/// <param name="cacheManager">Cache manager</param>
		/// <param name="xJEquipmentStockRepository">XJEquipmentStock repository</param>
		/// <param name="eventPublisher">Event published</param>
		public XJEquipmentStockService(ICacheManager cacheManager,
			IRepository<XJEquipmentStock> xJEquipmentStockRepository,
			IRepository<XJEquipment> xJEquipmentRepository,
			IRepository<XJPlace> xJPlaceRepository,
			IXJEquipmentCategoryService xJEquipmentCategoryService,
			IDbContext dbContext,
			IEventPublisher eventPublisher)
		{
			this._cacheManager = cacheManager;
			this._xJEquipmentStockRepository = xJEquipmentStockRepository;
			this._xJEquipmentRepository = xJEquipmentRepository;
			this._xJPlaceRepository = xJPlaceRepository;
			this._eventPublisher = eventPublisher;
			this._xJEquipmentCategoryService = xJEquipmentCategoryService;
			this._dbContext = dbContext;
		}

		#endregion

		#region Methods

		/// <summary>
		/// Gets all XJEquipmentStocks
		/// </summary>
		/// <returns>XJEquipmentStocks</returns>
		public virtual IList<XJEquipmentStock> GetAllXJEquipmentStocks()
		{
			string key = XJEQUIPMENTSTOCKS_ALL_KEY;
			return _cacheManager.Get(key, () =>
			{
				var query = from a in _xJEquipmentStockRepository.Table
							orderby a.Id
							select a;
				return query.ToList();
			});
		}

		public virtual IList<XJEquipmentStock> GetStocksByIds(int[] ids)
		{
			if (ids == null || ids.Length == 0)
				return new List<XJEquipmentStock>();

			var query = from c in _xJEquipmentStockRepository.Table
						where ids.Contains(c.Id)
						select c;
			return query.ToList();
		}

		public virtual IPagedList<XJEquipmentStockTemp> GetAllStocks(int categoryId = 0, int placeId = 0, int partnerId = 0, int equipmentId = 0, string keyword = "", string name = "", string pp = "", string gg = "", string xh = "", string location = "", bool showHidden = true, bool onlyStock = false, int state = 0, string sort = "", int pageIndex = 0, int pageSize = int.MaxValue)
		{
			var query = from s in _xJEquipmentStockRepository.Table
						join p in _xJEquipmentRepository.Table on s.EquipmentId equals p.Id into ptmp
						from pall in ptmp.DefaultIfEmpty()
						join l in _xJPlaceRepository.Table on s.PlaceId equals l.Id into ltmp
						from lall in ltmp.DefaultIfEmpty()
						select new XJEquipmentStockTemp
						{
							Id = s.Id,
							PlaceId = s.PlaceId,
							PlaceName = lall.Name,
							EquipmentId = s.EquipmentId,
							Name = s.Name,
							Manufacturer = s.Manufacturer,
							Specification = s.Specification,
							Unit = pall.Unit ?? "",
							Location = s.Location,
							CategoryId = pall.CategoryId,
							Stock = pall.Stock,
							DisplayOrder = pall.DisplayOrder,
							Published = pall.Published,
							Price = s.Price,
							Amount = s.Amount,
							Freeze = s.Freeze,
							CustomerId = s.CustomerId,
							CreatedOn = s.CreatedOn,
							StartOn = s.StartOn,
							EndOn = s.EndOn,
							State = s.State,
						};
			if (categoryId > 0)
			{
				var categoryIds = _xJEquipmentCategoryService.GetAllCategories(categoryId).Select(x => x.Id).ToArray();
				query = query.Where(m => categoryIds.Contains(m.CategoryId));
			}
			if (placeId > 0)
				query = query.Where(m => m.PlaceId == placeId);
			if (partnerId > 0)
			{
				string strSql = string.Format("WITH menu(Id)as( SELECT Id FROM XJEquipment WHERE Id = {0} Union All Select A.Id FROM XJEquipment A inner join menu B ON A.PId = B.Id) SELECT Id FROM menu", partnerId);
				var eIds = _dbContext.SqlQuery<int>(strSql).ToArray();
				if (eIds == null || eIds.Length == 0)
					query = query.Where(m => m.EquipmentId == partnerId);
				else
					query = query.Where(m => eIds.Contains(m.EquipmentId));
			}
			if (equipmentId > 0)
				query = query.Where(m => m.EquipmentId == equipmentId);
			if (!string.IsNullOrWhiteSpace(name))
				query = query.Where(c => c.Name.Contains(name));
			if (!string.IsNullOrWhiteSpace(pp))
				query = query.Where(c => c.Manufacturer.Contains(pp));
			if (!string.IsNullOrWhiteSpace(gg))
				query = query.Where(c => c.Specification.Contains(gg));
			if (!string.IsNullOrWhiteSpace(location))
				query = query.Where(c => c.Location.Contains(location));
			if (!string.IsNullOrEmpty(keyword))
			{
				query = query.Where(c => c.Name.Contains(keyword) || c.Manufacturer.Contains(keyword) || c.Specification.Contains(keyword) || c.Location.Contains(keyword));
			}
			if (!showHidden)
				query = query.Where(m => m.Published);
			if (onlyStock)
				query = query.Where(m => m.Stock > 0);
			if (state > 0)
				query = query.Where(m => m.State == state);
			switch (sort)
			{
				case "Name":
					query = query.OrderBy(m => m.Name).ThenByDescending(m => m.Id);
					break;
				default:
					query = query.OrderByDescending(m => m.Id);
					break;
			}

			//paging
			return new PagedList<XJEquipmentStockTemp>(query, pageIndex, pageSize);
		}

		/// <summary>
		/// Gets a XJEquipmentStock 
		/// </summary>
		/// <param name="xJEquipmentStockId">XJEquipmentStock identifier</param>
		/// <returns>XJEquipmentStock</returns>
		public virtual XJEquipmentStock GetXJEquipmentStockById(int xJEquipmentStockId)
		{
			if (xJEquipmentStockId == 0)
				return null;

			string key = string.Format(XJEQUIPMENTSTOCK_BY_ID_KEY, xJEquipmentStockId);
			return _cacheManager.Get(key, () => _xJEquipmentStockRepository.GetById(xJEquipmentStockId));
		}

		public virtual XJEquipmentStock GetXJEquipmentStockByInDetail(XJEquipmentStockInDetail detail)
		{
			var query = _xJEquipmentStockRepository.Table.FirstOrDefault(m => m.EquipmentId == detail.EquipmentId && m.Price == detail.Price);
			return query;
		}

		/// <summary>
		/// Inserts a XJEquipmentStock
		/// </summary>
		/// <param name="xJEquipmentStock">XJEquipmentStock</param>
		public virtual void InsertXJEquipmentStock(XJEquipmentStock xJEquipmentStock)
		{
			if (xJEquipmentStock == null)
				throw new ArgumentNullException("xJEquipmentStock");

			_xJEquipmentStockRepository.Insert(xJEquipmentStock);

			_cacheManager.RemoveByPattern(XJEQUIPMENTSTOCKS_PATTERN_KEY);

			//event notification
			_eventPublisher.EntityInserted(xJEquipmentStock);
		}

		/// <summary>
		/// Updates the XJEquipmentStock
		/// </summary>
		/// <param name="xJEquipmentStock">XJEquipmentStock</param>
		public virtual void UpdateXJEquipmentStock(XJEquipmentStock xJEquipmentStock)
		{
			if (xJEquipmentStock == null)
				throw new ArgumentNullException("xJEquipmentStock");

			_xJEquipmentStockRepository.Update(xJEquipmentStock);

			_cacheManager.RemoveByPattern(XJEQUIPMENTSTOCKS_PATTERN_KEY);

			//event notification
			_eventPublisher.EntityUpdated(xJEquipmentStock);
		}

		/// <summary>
		/// Deletes a XJEquipmentStock
		/// </summary>
		/// <param name="xJEquipmentStock">XJEquipmentStock</param>
		public virtual void DeleteXJEquipmentStock(XJEquipmentStock xJEquipmentStock)
		{
			if (xJEquipmentStock == null)
				throw new ArgumentNullException("xJEquipmentStock");

			_xJEquipmentStockRepository.Delete(xJEquipmentStock);

			_cacheManager.RemoveByPattern(XJEQUIPMENTSTOCKS_PATTERN_KEY);

			//event notification
			_eventPublisher.EntityDeleted(xJEquipmentStock);
		}

		#endregion
	}
}
